package com.xpec.c4.db.dao;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.TreeMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class PlayerLevelCalculator {
	
	private static Log log = LogFactory.getLog(PlayerLevelCalculator.class);

	/**
	 * key:目前等級
	 */
	public static final String LEVEL = "LEVEL";
	
	/**
	 * key:當前等級所累積的經驗值
	 */
	public static final String EXP_IN_CURRENT_LEVEL = "EXP_IN_CURRENT_LEVEL";
	
	/**
	 * key:到達下一級所需的經驗值
	 */
	public static final String EXP_TO_NEXT_LEVEL = "EXP_TO_NEXT_LEVEL";
	
	/**
	 * 等級經驗資訊<br>
	 * key:exp<br>
	 * value:level
	 */
	private NavigableMap<Long, Long> levelExpMap = new TreeMap<Long, Long>();
	
	/**
	 * 該等級到下一級所需經驗<br>
	 * key:level<br>
	 * value:exp
	 */
	private HashMap<Long, Long> toNextLevelExpMap = new HashMap<Long, Long>();
	
	/**
	 * 升到該級所需的累積經驗<br>
	 * key:level<br>
	 * value:exp
	 */
	private HashMap<Long, Long> totalExpForLevelMap = new HashMap<Long, Long>();
	
	/**
	 * 設定檔內累積的經驗值
	 */
	private Long totalExpInSetting = 0L;
	
	/**
	 * 設定檔之後規律的經驗值需求
	 */
	private Long ragularExpPerLevel = 0L;
	
	/**
	 * 從bin檔載入並且初始化
	 */
	public void initFromBin(HashMap<String, String> lowLevelNeedBet, Long levelNeedBet){
		if(levelNeedBet != null && levelNeedBet > 0){
			ragularExpPerLevel = levelNeedBet;
		}
		else{
			//預設是10萬
			ragularExpPerLevel = 100000L;
		}
		
		//0級升到1級參考regularExp，因為0->1是通過轉正式贈送的等級(經驗)
		add(ragularExpPerLevel, 0L);
		
		if(lowLevelNeedBet != null){
			
			//從1級開始
			for(Long level = 1L; level <= lowLevelNeedBet.size(); level++){
				
				String expStr = lowLevelNeedBet.get(level);
				if(expStr == null){
					break;
				}
				
				try {
					
					Long exp = Long.valueOf(expStr);
					add(exp, level);
					
				} catch (Exception e) {
					if(log.isErrorEnabled()){
						log.error("wrong setting type, level:"+level+", exp:"+expStr);
					}
					break;
				}
			}	
		}
	}
	
	/**
	 * 加入資訊
	 */
	private void add(Long exp, Long level) {
		
		//下一級需求經驗部分
		toNextLevelExpMap.put(level, exp);
		
		//累積經驗部分
		totalExpForLevelMap.put(level, totalExpInSetting);
		
		//等級經驗部分
		totalExpInSetting += exp;
		levelExpMap.put(totalExpInSetting, level);
	}
	
	/**
	 * 以目前累積的經驗值取得資訊
	 */
	public HashMap<String, Long> getInfosByTotalExp(BigDecimal playerExpBig){
		HashMap<String, Long> result = new HashMap<String, Long>();
		
		if(playerExpBig == null){
			return result;
		}
		
		//直接先轉成long來看(捨棄小數位去算)
		long playerExp = playerExpBig.longValue();
		
		//經驗值已經超過低等設定
		if(playerExp >= totalExpInSetting){

			//多出的經驗值
			long restExp = playerExp - totalExpInSetting;
			
			//算當前等級
			Long level = Long.valueOf(levelExpMap.size());
			level += (restExp / ragularExpPerLevel);
			
			//算當前等級經驗
			Long currentLevelExp = restExp % ragularExpPerLevel;
			
			result.put(LEVEL, level);
			result.put(EXP_IN_CURRENT_LEVEL, currentLevelExp);
			result.put(EXP_TO_NEXT_LEVEL, ragularExpPerLevel);
			
		}
		//還在設定區間的經驗值
		else{
			
			Entry<Long, Long> entry = levelExpMap.ceilingEntry(playerExp);
			if (entry != null) {
				
				//取得對應的等級，這裡理論上不會是null
				Long level = entry.getValue();
				
				//到下一級所需的經驗
				Long toNextLevelExp = toNextLevelExpMap.get(level);
				
				//算當前等級經驗
				Long currentLevelExp = toNextLevelExp - (entry.getKey() - playerExp);
				
				//已經達到升級經驗的話，就要往下一級算
				if(toNextLevelExp.equals(currentLevelExp)){
					level ++;
					currentLevelExp = 0L;
					toNextLevelExp = toNextLevelExpMap.get(level);
				}

				result.put(LEVEL, level);
				result.put(EXP_TO_NEXT_LEVEL, toNextLevelExp);
				result.put(EXP_IN_CURRENT_LEVEL, currentLevelExp);
			}
			
		}
		
		return result;
	}
	
	/**
	 * 升到該等級所需的最小經驗
	 */
	public Long getExpByLevel(Long level){
		Long exp = 0L;
		
		if(level != null && level >= 0){
			
			if(totalExpForLevelMap.containsKey(level)){
				exp = totalExpForLevelMap.get(level);
			}
			else{
				exp = totalExpInSetting;
				exp += (level - levelExpMap.size()) * ragularExpPerLevel;
			}
			
		}
		
		return exp;
	}
	
}
